PAGE 118,121
TITLE TEST4 ---- 06/10/85  POST AND BIOS UTILITY ROUTINES
.286C
.XLIST
INCLUDE DSEG.INC
INCLUDE POSTEQU.INC
INCLUDE SYSDATA.INC
.LIST
CODE	SEGMENT BYTE PUBLIC

	PUBLIC	BEEP
	PUBLIC	BLINK_INT
	PUBLIC	CMOS_READ
	PUBLIC	CMOS_WRITE
	PUBLIC	CONFIG_BAD
	PUBLIC	D11
	PUBLIC	DDS
	PUBLIC	DUMMY_RETURN_1
	PUBLIC	ERR_BEEP
	PUBLIC	E_MSG
	PUBLIC	INT_287
	PUBLIC	KBD_RESET
	PUBLIC	POST4
	PUBLIC	PROT_PRT_HEX
	PUBLIC	PROC_SHUTDOWN
	PUBLIC	PRT_HEX
	PUBLIC	PRT_SEG
	PUBLIC	P_MSG
	PUBLIC	RE_DIRECT
	PUBLIC	ROM_CHECK
	PUBLIC	ROM_CHECKSUM
	PUBLIC	SET_TOD
	PUBLIC	WAITF
	PUBLIC	XPC_BYTE

	EXTRN	E163:NEAR
	EXTRN	OBF_42:NEAR
	EXTRN	ROM_ERR:NEAR
	EXTRN	XMIT_8042:NEAR

	ASSUME	CS:CODE,DS:DATA
POST4:
;--- CMOS_READ -----------------------------------------------------------------
;		READ BYTE FROM CMOS_SYSTEM CLOCK CONFIGURATION TABLE	       :
;									       :
; INPUT: (AL)=	CMOS_TABLE ADDRESS TO BE READ				       :
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT    :
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ		       :
;									       :
; OUTPUT: (AL)	VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS   :
;		ON THEN NMI LEFT DISABLED, DURING THE CMOS READ BOTH NMI AND   :
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND    :
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.      :
;		ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED.	       :
;-------------------------------------------------------------------------------

CMOS_READ	PROC	NEAR		;	READ LOCATION (AL) INTO (AL)
	PUSHF				; SAVE INTERRUPT ENABLE STATUS AND FLAGS
	ROL	AL,1			; MOVE NMI BIT TO LOW POSITION
	STC				; FORCE NMI BIT ON IN CARRY FLAG
	RCR	AL,1			; HIGH BIT ON TO DISABLE NMI - OLD IN CY
	CLI				; DISABLE INTERRUPTS
	OUT	CMOS_PORT,AL		; ADDRESS LOCATION AND DISABLE NMI
	NOP				; I/O DELAY
	IN	AL,CMOS_DATA		; READ THE REQUESTED CMOS LOCATION
	PUSH	AX			; SAVE (AH) REGISTER VALUE AND CMOS BYTE
	MOV	AL,CMOS_REG_D*2 	; GET ADDRESS OF DEFAULT LOCATION
	RCR	AL,1			; PUT ORIGINAL NMI MASK BIT INTO ADDRESS
	OUT	CMOS_PORT,AL		; SET DEFAULT TO READ ONLY REGISTER
	POP	AX			; RESTORE (AH) AND (AL), CMOS BYTE
	PUSH	CS			; *PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF		; *HANDLE POPF FOR B- LEVEL 80286
	RET				; RETURN WITH FLAGS RESTORED

CMOS_READ	ENDP

CMOS_POPF	PROC	NEAR		; POPF FOR LEVEL B- PARTS
	IRET				; RETURN FAR AND RESTORE FLAGS
CMOS_POPF	ENDP

;--- CMOS_WRITE ----------------------------------------------------------------
;	WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE		       :
;									       :
; INPUT: (AL)=	CMOS TABLE ADDRESS TO BE WRITTEN TO			       :
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT    :
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE		       :
;	 (AH)=	NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION	       :
;									       :
; OUTPUT:	VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED   :
;		IF BIT 7 OF (AL) IS ON, DURING THE CMOS UPDATE BOTH NMI AND    :
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND    :
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.      :
;		ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED.	       :
;-------------------------------------------------------------------------------

CMOS_WRITE	PROC	NEAR		;	WRITE (AH) TO LOCATION (AL)
	PUSHF				; SAVE INTERRUPT ENABLE STATUS AND FLAGS
	PUSH	AX			; SAVE WORK REGISTER VALUES
	ROL	AL,1			; MOVE NMI BIT TO LOW POSITION
	STC				; FORCE NMI BIT ON IN CARRY FLAG
	RCR	AL,1			; HIGH BIT ON TO DISABLE NMI - OLD IN CY
	CLI				; DISABLE INTERRUPTS
	OUT	CMOS_PORT,AL		; ADDRESS LOCATION AND DISABLE NMI
	MOV	AL,AH			; GET THE DATA BYTE TO WRITE
	OUT	CMOS_DATA,AL		; PLACE IN REQUESTED CMOS LOCATION
	MOV	AL,CMOS_REG_D*2 	; GET ADDRESS OF DEFAULT LOCATION
	RCR	AL,1			; PUT ORIGINAL NMI MASK BIT INTO ADDRESS
	OUT	CMOS_PORT,AL		; SET DEFAULT TO READ ONLY REGISTER
	POP	AX			; RESTORE WORK REGISTERS
	PUSH	CS			; *PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF		; *HANDLE POPF FOR B- LEVEL 80286
	RET

CMOS_WRITE	ENDP
PAGE
DDS	PROC	NEAR			;	LOAD (DS) TO DATA AREA
	MOV	DS,CS:DDSDATA		; PUT SEGMENT VALUE OF DATA AREA INTO DS
	RET				; RETURN TO USER WITH (DS)= DATA

DDSDATA DW	DATA			; SEGMENT SELECTOR VALUE FOR DATA AREA

DDS	ENDP

;--- E_MSG -- P MSG -----------------------------------------------------
;	THIS SUBROUTINE WILL PRINT A MESSAGE ON THE DISPLAY		:
;									:
; ENTRY REQUIREMENTS:							:
;	SI = OFFSET(ADDRESS) OF MESSAGE BUFFER				:
;	CX = MESSAGE BYTE COUNT 					:
;	     MAXIMUM MESSAGE LENGTH IS 36 CHARACTERS			:
;	BP = BIT 0=E161/E162, BIT 1=CONFIG_BAD, 2-15= FIRST MSG OFFSET	:
;------------------------------------------------------------------------

E_MSG	PROC	NEAR
	TEST	BP,03FFFH		; CHECK FOR NOT FIRST ERROR MESSAGE
	JNZ	E_MSG1			; SKIP IF NOT FIRST ERROR MESSAGE

	PUSH	SI			; SAVE MESSAGE POINTER
	AND	SI,03FFFH		; USE LOW 14 BITS OF MESSAGE OFFSET
	OR	BP,SI			;  AS FIRST ERROR MESSAGE FLAG
	POP	SI			; (BIT 0 = E161/E162, BIT 1 = BAD_CONFIG
E_MSG1:
	CALL	P_MSG			; PRINT MESSAGE
	PUSH	DS			; SAVE CALLERS (DS)
	CALL	DDS			; POINT TO POST/BIOS DATA SEGMENT
	TEST	BYTE PTR @EQUIP_FLAG,01H; LOOP/HALT ON ERROR SWITCH ON ?
	JZ	MFG_HALT		; YES - THEN GO TO MANUFACTURING HALT

	POP	DS			; RESTORE CALLERS (DS)
	RET

MFG_HALT:				; MANUFACTURING LOOP MODE ERROR TRAP
	CLI				; DISABLE INTERRUPTS
	MOV	AL,@MFG_ERR_FLAG	; RECOVER ERROR INDICATOR
	OUT	MFG_PORT,AL		; SET INTO MANUFACTURING PORT
	HLT				; HALT SYSTEM
	JMP	MFG_HALT		; HOT NMI TRAP

E_MSG	ENDP


P_MSG	PROC	NEAR			;	DISPLAY STRING FROM (CS:)
	MOV	AL,CS:[SI]		; PUT CHARACTER IN (AL)
	INC	SI			; POINT TO NEXT CHARACTER
	PUSH	AX			; SAVE PRINT CHARACTER
	CALL	PRT_HEX 		; CALL VIDEO_IO
	POP	AX			; RECOVER PRINT CHARACTER
	CMP	AL,LF			; WAS IT LINE FEED?
	JNE	P_MSG			; NO, KEEP PRINTING STRING
	RET

P_MSG	ENDP

;--- ERR_BEEP -----------------------------------------------------------
;	THIS PROCEDURE WILL ISSUE LONG TONES (1-3/4 SECONDS) AND ONE OR :
;	MORE SHORT TONES (9/32 SECOND) TO INDICATE A FAILURE ON THE	:
;	PLANAR BOARD, A BAD MEMORY MODULE, OR A PROBLEM WITH THE CRT.	:
; ENTRY PARAMETERS:							:
;	DH = NUMBER OF LONG TONES TO BEEP.				:
;	DL = NUMBER OF SHORT TONES TO BEEP.				:
;------------------------------------------------------------------------

ERR_BEEP	PROC	NEAR
	PUSHF				; SAVE FLAGS
	CLI				; DISABLE SYSTEM INTERRUPTS
	OR	DH,DH			; ANY LONG ONES TO BEEP
	JZ	G3			; NO, DO THE SHORT ONES
G1:					;	LONG BEEPS
	MOV	BL,112			; COUNTER FOR LONG BEEPS (1-3/4 SECONDS)
	MOV	CX,1280 		; DIVISOR FOR 932 HZ
	CALL	BEEP			; DO THE BEEP
	MOV	CX,49715		; 2/3 SECOND DELAY AFTER LONG BEEP
	CALL	WAITF			; DELAY BETWEEN BEEPS
	DEC	DH			; ANY MORE LONG BEEPS TO DO
	JNZ	G1			; LOOP TILL DONE

	PUSH	DS			; SAVE DS REGISTER CONTENTS
	CALL	DDS
	CMP	@MFG_TST,01H		; MANUFACTURING TEST MODE?
	POP	DS			; RESTORE ORIGINAL CONTENTS OF (DS)
	JE	MFG_HALT		; YES - STOP BLINKING LED

G3:					;	SHORT BEEPS
	MOV	BL,18			; COUNTER FOR A SHORT BEEP (9/32)
	MOV	CX,1208 		; DIVISOR FOR 987 HZ
	CALL	BEEP			; DO THE SOUND
	MOV	CX,33144		; 1/2 SECOND DELAY AFTER SHORT BEEP
	CALL	WAITF			; DELAY BETWEEN BEEPS
	DEC	DL			; DONE WITH SHORT BEEPS COUNT
	JNZ	G3			; LOOP TILL DONE

	MOV	CX,33144		; 1/2 SECOND DELAY AFTER LAST BEEP
	CALL	WAITF			; MAKE IT ONE SECOND DELAY BEFORE RETURN
	POPF				; RESTORE FLAGS TO ORIGINAL SETTINGS
	RET				; RETURN TO CALLER

ERR_BEEP	ENDP
PAGE
;--- BEEP ---------------------------------------------------------------
;	ROUTINE TO SOUND THE BEEPER USING TIMER 2 FOR TONE		:
; ENTRY:								:
;	(BL) = DURATION COUNTER ( 1 FOR 1/64 SECOND )			:
;	(CX) = FREQUENCY DIVISOR (1193180/FREQUENCY) (1331 FOR 886 HZ)	:
; EXIT: 								:
;	(AX),(BL),(CX) MODIFIED.					:
;------------------------------------------------------------------------

BEEP	PROC	NEAR			;	SETUP TIMER 2
	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	MOV	AL,10110110B		; SELECT TIMER 2,LSB,MSB,BINARY
	OUT	TIMER+3,AL		; WRITE THE TIMER MODE REGISTER
	JMP	$+2			; I/O DELAY
	MOV	AL,CL			; DIVISOR FOR HZ (LOW)
	OUT	TIMER+2,AL		; WRITE TIMER 2 COUNT - LSB
	JMP	$+2			; I/O DELAY
	MOV	AL,CH			; DIVISOR FOR HZ (HIGH)
	OUT	TIMER+2,AL		; WRITE TIMER 2 COUNT - MSB
	IN	AL,PORT_B		; GET CURRENT SETTING OF PORT
	MOV	AH,AL			; SAVE THAT SETTING
	OR	AL,GATE2+SPK2		; GATE TIMER 2 AND TURN SPEAKER ON
	OUT	PORT_B,AL		; AND RESTORE INTERRUPT STATUS
	POPF
G7:					;	1/64 SECOND PER COUNT (BL)
	MOV	CX,1035 		; DELAY COUNT FOR 1/64 OF A SECOND
	CALL	WAITF			; GO TO BEEP DELAY 1/64 COUNT
	DEC	BL			; (BL) LENGTH COUNT EXPIRED?
	JNZ	G7			; NO - CONTINUE BEEPING SPEAKER

	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B		; GET CURRENT PORT VALUE
	OR	AL,NOT (GATE2+SPK2)	; ISOLATE CURRENT SPEAKER BITS N CASE
	AND	AH,AL			;  SOMEONE TURNED THEM OFF DURING BEEP
	MOV	AL,AH			; RECOVER VALUE OF PORT
	AND	AL,NOT (GATE2+SPK2)	; FORCE SPEAKER DATA OFF
	OUT	PORT_B,AL		; AND STOP SPEAKER TIMER
	POPF				; RESTORE INTERRUPT FLAG STATE
	MOV	CX,1035 		; FORCE 1/64 SECOND DELAY (SHORT)
	CALL	WAITF			; MINIMUM DELAY BETWEEN ALL BEEPS
	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B		; GET CURRENT PORT VALUE IN CASE
	AND	AL,GATE2+SPK2		;  SOMEONE TURNED THEM ON
	OR	AL,AH			; RECOVER VALUE OF PORT_B
	OUT	PORT_B,AL		; RESTORE SPEAKER STATUS
	POPF				; RESTORE INTERRUPT FLAG STATE
	RET

BEEP	ENDP

;--- WAITF -------------------------------------------------------------
;	FIXED TIME WAIT ROUTINE HARDWARE CONTROLLED - NOT PROCESSOR)   :
;								       :
; ENTRY:							       :
;	(CX) = COUNT OF 15.085737 MICROSECOND INTERVALS TO WAIT        :
;		MEMORY REFRESH TIMER 1 OUTPUT USED AS REFERENCE        :
; EXIT: 							       :
;		AFTER (CX) TIME COUNT (PLUS OR MINUS 16 MICROSECONDS)  :
;	(CX) = 0						       :
;-----------------------------------------------------------------------

WAITF	PROC	NEAR			;	DELAY FOR (CX)*15.085737 US
	PUSH	AX			; SAVE WORK REGISTER (AH)

WAITF1: 				;	USE TIMER 1 OUTPUT BITS
	IN	AL,PORT_B		; READ CURRENT COUNTER OUTPUT STATUS
	AND	AL,REFRESH_BIT		; MASK FOR REFRESH DETERMINE BIT
	CMP	AL,AH			; DID IT JUST CHANGE
	JE	WAITF1			; WAIT FOR A CHANGE IN OUTPUT LINE

	MOV	AH,AL			; SAVE NEW FLAG STATE
	LOOP	WAITF1			; DECREMENT HALF CYCLES TILL COUNT END

	POP	AX			; RESTORE (AH)
	RET				; RETURN (CX)= 0

WAITF	ENDP

;--- CONFIG_BAD ----------------------------------------------------------
;	SET CMOS_DIAG WITH CONFIG ERROR BIT (WITH NMI DISABLED) 	 :
;	(BP) BIT 14 SET ON TO INDICATE CONFIGURATION ERROR		 :
;-------------------------------------------------------------------------

CONFIG_BAD	PROC	NEAR
	PUSH	AX
	MOV	AX,X*(CMOS_DIAG+NMI)	; ADDRESS CMOS DIAGNOSTIC STATUS BYTE
	CALL	CMOS_READ		; GET CURRENT VALUE
	OR	AL,BAD_CONFIG		; SET BAD CONFIGURATION BIT
	XCHG	AH,AL			; SETUP FOR WRITE
	CALL	CMOS_WRITE		; UPDATE CMOS WITH BAD CONFIGURATION
	POP	AX
	OR	BP,04000H		; SET CONFIGURATION BAD FLAG IN (BP)
	RET

CONFIG_BAD	ENDP
PAGE
;--- XPC_BYTE -- XLATE_PR -- PRT_HEX -------------------------------------
;									 :
;	CONVERT AND PRINT ASCII CODE CHARACTERS 			 :
;									 :
;	AL CONTAINS NUMBER TO BE CONVERTED.				 :
;	AX AND BX DESTROYED.						 :
;-------------------------------------------------------------------------

XPC_BYTE	PROC	NEAR		;	DISPLAY TWO HEX DIGITS
	PUSH	AX			; SAVE FOR LOW NIBBLE DISPLAY
	SHR	AL,4			; NIBBLE SWAP
	CALL	XLAT_PR 		; DO THE HIGH NIBBLE DISPLAY
	POP	AX			; RECOVER THE NIBBLE
	AND	AL,0FH			; ISOLATE TO LOW NIBBLE
					; FALL INTO LOW NIBBLE CONVERSION

XLAT_PR PROC	NEAR			;	CONVERT 00-0F TO ASCII CHARACTER
	ADD	AL,090H 		; ADD FIRST CONVERSION FACTOR
	DAA				; ADJUST FOR NUMERIC AND ALPHA RANGE
	ADC	AL,040H 		; ADD CONVERSION AND ADJUST LOW NIBBLE
	DAA				; ADJUST HIGH NIBBLE TO ASCII RANGE

PRT_HEX PROC	NEAR
	MOV	AH,0EH			; DISPLAY CHARACTER IN (AL) COMMAND
	MOV	BH,0
	INT	10H			; CALL VIDEO_IO
	RET

PRT_HEX ENDP
XLAT_PR ENDP
XPC_BYTE	ENDP

;--- PRT_SEG ----------------------------------------------------
;	PRINT A SEGMENT VALUE TO LOOK LIKE A 21 BIT ADDRESS	:
;	DX MUST CONTAIN SEGMENT VALUE TO BE PRINTED		:
;----------------------------------------------------------------

PRT_SEG PROC	NEAR
	MOV	AL,DH			; GET MSB
	CALL	XPC_BYTE		; DISPLAY SEGMENT HIGH BYTE
	MOV	AL,DL			; LSB
	CALL	XPC_BYTE		; DISPLAY SEGMENT LOW BYTE
	MOV	AL,'0'                  ; PRINT A '0 '
	CALL	PRT_HEX 		;  TO MAKE LOOK LIKE ADDRESS
	MOV	AL,' '                  ; ADD ENDING SPACE
	CALL	PRT_HEX
	RET

PRT_SEG 	ENDP

;--- PROT_PRT_HEX -------------------------------------------------------
;									:
;	PUT A CHARACTER TO THE DISPLAY BUFFERS WHEN IN PROTECTED MODE	:
;									:
;	(AL)= ASCII CHARACTER						:
;	(DI)= DISPLAY REGEN BUFFER POSITION				:
;------------------------------------------------------------------------

PROT_PRT_HEX	PROC	NEAR
	PUSH	ES			; SAVE CURRENT SEGMENT REGISTERS
	PUSH	DI
	SAL	DI,1			; MULTIPLY OFFSET BY TWO

;-----	MONOCHROME VIDEO CARD

	PUSH	BYTE PTR C_BWCRT_PTR	; GET MONOCHROME BUFFER SEGMENT SELECTOR
	POP	ES			; SET (ES) TO B/W DISPLAY BUFFER
	STOSB				; PLACE CHARACTER IN SUPPER
	DEC	DI			; ADJUST POINTER BACK

; ----- ENHANCED GRAPHICS ADAPTER

	PUSH	BYTE PTR E_CCRT_PTR	; ENHANCED COLOR DISPLAY POINTER LOW 64K
	POP	ES			; LOAD SEGMENT SELECTOR
	STOSB				; PLACE CHARACTER IN BUFFER
	DEC	DI			; ADJUST POINTER BACK
	PUSH	BYTE PTR E_CCRT_PTR2	; ENHANCED COLOR DISPLAY POINTER HI 64K
	POP	ES			; LOAD SEGMENT SELECTOR
	STOSB				; PLACE CHARACTER IN BUFFER
	DEC	DI			; ADJUST POINTER BACK

;-----	COMPATIBLE COLOR

	PUSH	BYTE PTR C_CCRT_PTR	; SET (DS) TO COMPATIBLE COLOR MEMORY
	POP	ES
	PUSH	BX			; SAVE WORK REGISTERS
	PUSH	DX
	PUSH	CX
	XOR	CX,CX			; TIMEOUT LOOP FOR "BAD" HARDWARE
	MOV	DX,03DAH		; STATUS ADDRESS OF COLOR CARD
	XCHG	AX,BX			; SAVE IN (BX) REGISTER
PROT_S:
	IN	AL,DX			; GET COLOR CARD STATUS
	TEST	AL,RVRT+RHRZ		; CHECK FOR VERTICAL RETRACE (OR HORZ)
	LOOPZ	PROT_S			; TIMEOUT LOOP TILL FOUND
	XCHG	AX,BX			; RECOVER CHARACTERS
	STOSB				; PLACE CHARACTER IN BUFFER
	POP	CX			; RESTORE REGISTERS
	POP	DX
	POP	BX
	POP	DI
	POP	ES
	RET

PROT_PRT_HEX	ENDP
PAGE
;----------------------------------------
;	ROM CHECKSUM SUBROUTINE 	:
;----------------------------------------

ROM_CHECKSUM	PROC	NEAR
	SUB	CX,CX			; NUMBER OF BYTES TO ADD IS 64K

ROM_CHECKSUM_CNT:			; ENTRY FOR OPTIONAL ROM TEST
	XOR	AL,AL
ROM_L:
	ADD	AL,[BX] 		; GET (DS:BX)
	INC	BX			; POINT TO NEXT BYTE
	LOOP	ROM_L			; ADD ALL BYTES IN ROM MODULE

	OR	AL,AL			; SUM = 0?
	RET

ROM_CHECKSUM	ENDP

;------------------------------------------------------------------------
;	THIS ROUTINE CHECKSUMS OPTIONAL ROM MODULES AND 		:
;	IF CHECKSUM IS OK, CALLS INITIALIZATION/TEST CODE IN MODULE	:
;------------------------------------------------------------------------

ROM_CHECK	PROC	NEAR
	MOV	AX,DATA 		; POINT ES TO DATA AREA
	MOV	ES,AX
	SUB	AH,AH			; ZERO OUT AH
	MOV	AL,[BX+2]		; GET LENGTH INDICATOR
	SHL	AX,9			; MULTIPLY BY 512
	MOV	CX,AX			; SET COUNT
	SHR	AX,4
	ADD	DX,AX			; SET POINTER TO NEXT MODULE
	CALL	ROM_CHECKSUM_CNT	; DO CHECKSUM
	JZ	ROM_CHECK_1

	CALL	ROM_ERR 		; POST CHECKSUM ERROR
	JMP	SHORT ROM_CHECK_END	; AND EXIT

ROM_CHECK_1:
	PUSH	DX			; SAVE POINTER
	MOV	ES:@IO_ROM_INIT,0003H	; LOAD OFFSET
	MOV	ES:@IO_ROM_SEG,DS	; LOAD SEGMENT
	CALL	DWORD PTR ES:@IO_ROM_INIT	; CALL INITIALIZE/TEST ROUTINE
	POP	DX

ROM_CHECK_END:
	RET				; RETURN TO CALLER

ROM_CHECK	ENDP

;--- KBD_RESET-----------------------------------------------------------
;	THIS PROCEDURE WILL SEND A SOFTWARE RESET TO THE KEYBOARD.	:
;	SCAN CODE 0AAH SHOULD BE RETURNED TO THE PROCESSOR.		:
;	SCAN CODE 065H IS DEFINED FOR MANUFACTURING TEST		:
;------------------------------------------------------------------------

KBD_RESET	PROC	NEAR
	MOV	AL,0FFH 		; SET KEYBOARD RESET COMMAND
	CALL	XMIT_8042		; GO ISSUE THE COMMAND
	JCXZ	G13			; EXIT IF ERROR

	CMP	AL,KB_ACK
	JNZ	G13

	MOV	AL,0FDH 		; ENABLE KEYBOARD INTERRUPTS
	OUT	INTA01,AL		; WRITE 8259 INTERRUPT MASK REGISTER
	MOV	@INTR_FLAG,0		; RESET INTERRUPT INDICATOR
	STI				; ENABLE INTERRUPTS
	MOV	BL,10			; TRY FOR 400 MILLISECONDS
	SUB	CX,CX			; SETUP INTERRUPT TIMEOUT COUNT
G11:
	TEST	@INTR_FLAG,02H		; DID A KEYBOARD INTERRUPT OCCUR ?
	JNZ	G12			; YES - READ SCAN CODE RETURNED
	LOOP	G11			; NO - LOOP TILL TIMEOUT

	DEC	BL
	JNZ	G11			; TRY AGAIN
G12:
	IN	AL,PORT_A		; READ KEYBOARD SCAN CODE
	MOV	BL,AL			; SAVE SCAN CODE JUST READ
G13:
	RET				; RETURN TO CALLER

KBD_RESET	ENDP

;-------------------------------------------------------
;	BLINK LED PROCEDURE FOR MFG RUN-IN TESTS       :
;	 IF LED IS ON, TURN IT OFF. IF OFF, TURN ON.   :
;-------------------------------------------------------

BLINK_INT	PROC	NEAR
	STI
	PUSH	AX			; SAVE AX REGISTER CONTENTS
	IN	AL,MFG_PORT		; READ CURRENT VALUE OF MFG_PORT
	XOR	AL,01000000B		; FLIP CONTROL BIT
	OUT	MFG_PORT,AL
	MOV	AL,EOI
	OUT	INTA00,AL
	POP	AX			; RESTORE AX REGISTER
	IRET

BLINK_INT	ENDP
PAGE
;-------------------------------------------------------------------------------
;	THIS ROUTINE INITIALIZES THE TIMER DATA AREA IN THE ROM BIOS	       :
;	DATA AREA.  IT IS CALLED BY THE POWER ON ROUTINES.  IT CONVERTS        :
;	HR:MIN:SEC  FROM CMOS TO TIMER TICS. IF CMOS IS INVALID, TIMER	       :
;	IS SET TO ZERO. 						       :
;									       :
; INPUT    NONE PASSED TO ROUTINE BY CALLER				       :
;	   CMOS LOCATIONS USED FOR TIME 				       :
;									       :
; OUTPUT   @TIMER_LOW							       :
;	   @TIMER_HIGH							       :
;	   @TIMER_OFL							       :
;	   ALL REGISTERS UNCHANGED					       :
;-------------------------------------------------------------------------------

COUNTS_SEC	EQU	18		; TIMER DATA CONVERSION EQUATES
COUNTS_MIN	EQU	1092
COUNTS_HOUR	EQU	7		; 65543 - 65536
UPDATE_TIMER	EQU	10000000B	; RTC UPDATE IN PROCESS BIT MASK

SET_TOD PROC	NEAR
	PUSHA
	PUSH	DS
	CALL	DDS			; ESTABLISH SEGMENT
	SUB	AX,AX
	MOV	@TIMER_OFL,AL		; RESET TIMER ROLL OVER INDICATOR
	MOV	@TIMER_LOW,AX		; AND TIMER COUNT
	MOV	@TIMER_HIGH,AX
	MOV	AL,CMOS_DIAG+NMI	; CHECK CMOS VALIDITY
	CALL	CMOS_READ		; READ DIAGNOSTIC LOCATION IN CMOS
	AND	AL,BAD_BAT+BAD_CKSUM+CMOS_CLK_FAIL
	SUB	CX,CX			; BAD BATTERY, CHKSUM ERROR, CLOCK ERROR
	JNZ	POD_DONE		; CMOS NOT VALID -- TIMER SET TO ZERO
UIP:
	MOV	AL,CMOS_REG_A+NMI	; ACCESS REGISTER A
	CALL	CMOS_READ		; READ CMOS CLOCK REGISTER A
	TEST	AL,UPDATE_TIMER
	LOOPZ	UIP			; WAIT TILL UPDATE BIT IS ON

	JCXZ	POD_DONE		; CMOS CLOCK STUCK IF TIMEOUT
UIPOFF:
	MOV	AL,CMOS_REG_A+NMI	; ACCESS REGISTER A
	CALL	CMOS_READ		; READ CMOS CLOCK REGISTER A
	TEST	AL,UPDATE_TIMER
	LOOPNZ	UIPOFF			; NEXT WAIT TILL END OF UPDATE

	JCXZ	POD_DONE		; CMOS CLOCK STUCK IF TIMEOUT

	MOV	AL,CMOS_SECONDS+NMI	;	TIME JUST UPDATED
	CALL	CMOS_READ		; ACCESS SECONDS VALUE IN CMOS
	CMP	AL,59H			; ARE THE SECONDS WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT

	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	MOV	CX,AX			; MOVE COUNT TO ACCUMULATION REGISTER
	SHR	CX,2			; ADJUST FOR SYSTEMATIC SECONDS ERROR
	MOV	BL,COUNTS_SEC
	MUL	BL			; COUNT FOR SECONDS
	ADD	CX,AX
	MOV	AL,CMOS_MINUTES+NMI
	CALL	CMOS_READ		; ACCESS MINUTES VALUE IN CMOS
	CMP	AL,59H			; ARE THE MINUTES WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT
	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	PUSH	AX			; SAVE MINUTES COUNT
	SHR	AX,1			; ADJUST FOR SYSTEMATIC MINUTES ERROR
	ADD	CX,AX			; ADD ADJUSTMENT TO COUNT
	POP	AX			; RECOVER BCD MINUTES VALUE
	MOV	BX,COUNTS_MIN
	MUL	BX			; COUNT FOR MINUTES
	ADD	CX,AX			; ADD TO ACCUMULATED VALUE
	MOV	AL,CMOS_HOURS+NMI
	CALL	CMOS_READ		; ACCESS HOURS VALUE IN CMOS
	CMP	AL,23H			; ARE THE HOURS WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT

	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	MOV	DX,AX
	MOV	BL,COUNTS_HOUR
	MUL	BL			; COUNT FOR HOURS
	ADD	AX,CX
	ADC	DX,0000H
	MOV	@TIMER_HIGH,DX
	MOV	@TIMER_LOW,AX
POD_DONE:
	POP	DS
	POPA
	RET

TOD_ERROR:
	POP	DS			; RESTORE SEGMENT
	POPA				; RESTORE REGISTERS
	MOV	SI,OFFSET E163		; DISPLAY CLOCK ERROR
	CALL	E_MSG
	MOV	AX,X*(CMOS_DIAG+NMI)	; SET CLOCK ERROR IN STATUS
	CALL	CMOS_READ		; READ DIAGNOSTIC CMOS LOCATION
	OR	AL,CMOS_CLK_FAIL	; SET NEW STATUS WITH CMOS CLOCK ERROR
	XCHG	AL,AH			; MOVE NEW STATUS TO WORK REGISTER
	CALL	CMOS_WRITE		; UPDATE STATUS LOCATION
	RET

SET_TOD 	ENDP

CVT_BINARY	PROC	NEAR
	MOV	AH,AL			; UNPACK 2 BCD DIGITS IN AL
	SHR	AH,4
	AND	AL,0FH			; RESULT IS IN AX
	AAD				; CONVERT UNPACKED BCD TO BINARY
	RET

CVT_BINARY	ENDP
PAGE
;--- D11 -- INT ?? H - ( IRQ LEVEL ?? ) ----------------------------------------
; TEMPORARY INTERRUPT SERVICE ROUTINE FOR POST				       :
;									       :
;	THIS ROUTINE IS ALSO LEFT IN PLACE AFTER THE POWER ON DIAGNOSTICS      :
;	TO SERVICE UNUSED INTERRUPT VECTORS.  LOCATION "@INTR_FLAG" WILL       :
;	CONTAIN EITHER: 						       :
;	 1) LEVEL OF HARDWARE INTERRUPT THAT CAUSED CODE TO BE EXECUTED, OR    :
;	 2) "FF" FOR A NON-HARDWARE INTERRUPT THAT WAS EXECUTED ACCIDENTALLY.  :
;-------------------------------------------------------------------------------

D11	PROC	NEAR
	PUSH	AX			; SAVE REGISTER AX CONTENTS
	PUSH	BX
	MOV	AL,0BH			; READ IN-SERVICE REGISTER
	OUT	INTA00,AL		; (FIND OUT WHAT LEVEL BEING
	JMP	$+2			;  SERVICED)
	IN	AL,INTA00		; GET LEVEL
	MOV	AH,AL			; SAVE IT
	OR	AL,AH			; 00? (NO HARDWARE ISR ACTIVE)
	JNZ	HW_INT

	MOV	AH,0FFH
	JMP	SHORT SET_INTR_FLAG	; SET FLAG TO "FF" IF NON-HARDWARE
HW_INT:
	MOV	AL,0BH			; READ IN-SERVICE REGISTER FROM
	OUT	INTB00,AL		; INTERRUPT CHIP #2
	JMP	$+2			; I/O DELAY
	IN	AL,INTB00		; CHECK THE SECOND INTERRUPT CHIP
	MOV	BH,AL			; SAVE IT
	OR	BH,BH
	JZ	NOT_SEC 		; CONTINUE IF NOT

	IN	AL,INTB01		; GET SECOND INTERRUPT MASK
	OR	AL,BH			; MASK OFF LEVEL BEING SERVICED
	JMP	$+2			; I/O DELAY
	OUT	INTB01,AL
	MOV	AL,EOI			; SEND EOI TO SECOND CHIP
	JMP	$+2			; I/O DELAY
	OUT	INTB00,AL
	JMP	SHORT IS_SEC
NOT_SEC:
	IN	AL,INTA01		; GET CURRENT MASK VALUE
	JMP	$+2			; I/O DELAY
	AND	AH,0FBH 		; DO NOT DISABLE SECOND CONTROLLER
	OR	AL,AH			; MASK OFF LEVEL BEING SERVICED
	OUT	INTA01,AL		; SET NEW INTERRUPT MASK
	JMP	$+2			; I/O DELAY
IS_SEC:
	MOV	AL,EOI
	OUT	INTA00,AL
SET_INTR_FLAG:
	POP	BX			; RESTORE (BX) FROM STACK
	PUSH	DS			; SAVE ACTIVE (DS)
	CALL	DDS			; SET DATA SEGMENT
	MOV	@INTR_FLAG,AH		; SET FLAG
	POP	DS
	POP	AX			; RESTORE REGISTER AX CONTENTS
DUMMY_RETURN_1: 			; NEED IRET FOR VECTOR TABLE
	IRET

D11	ENDP

;--- HARDWARE INT 71 H -- ( IRQ LEVEL	9 ) -- TO INT  0A H -------------------
; REDIRECT SLAVE INTERRUPT 9 TO INTERRUPT LEVEL 2			      :
;	THIS ROUTINE FIELDS LEVEL 9 INTERRUPTS AND			      :
;	CONTROL IS PASSED TO MASTER INTERRUPT LEVEL 2			      :
;------------------------------------------------------------------------------

RE_DIRECT PROC	NEAR
	PUSH	AX			; SAVE (AX)
	MOV	AL,EOI
	OUT	INTB00,AL		; EOI TO SLAVE INTERRUPT CONTROLLER
	POP	AX			; RESTORE [AX]
	INT	0AH			; GIVE CONTROL TO HARDWARE LEVEL 2

	IRET				; RETURN

RE_DIRECT ENDP

;--- HARDWARE INT 75 H -- ( IRQ LEVEL 13 ) ------------------------------------
; SERVICE X287 INTERRUPTS						      :
;	THIS ROUTINE FIELDS X287 INTERRUPTS AND CONTROL 		      :
;	IS PASSED TO THE NMI INTERRUPT HANDLER FOR			      :
;	COMPATIBILITY.							      :
;------------------------------------------------------------------------------

INT_287 PROC	NEAR
	PUSH	AX			; SAVE (AX)
	XOR	AL,AL
	OUT	X287,AL 		; REMOVE THE INTERRUPT REQUEST

	MOV	AL,EOI			; ENABLE THE INTERRUPT
	OUT	INTB00,AL		;  THE SLAVE
	OUT	INTA00,AL		;  THE MASTER
	POP	AX			; RESTORE (AX)
	INT	02H			; GIVE CONTROL TO NMI

	IRET				; RETURN

INT_287 ENDP

PROC_SHUTDOWN	PROC			;	COMMON 80286 SHUTDOWN WAIT

	MOV	AL,SHUT_CMD		; SHUTDOWN COMMAND
	OUT	STATUS_PORT,AL		; SEND TO KEYBOARD CONTROL PORT
PROC_S:
	HLT				; WAIT FOR 80286 RESET
	JMP	PROC_S			; INSURE HALT

PROC_SHUTDOWN	ENDP
CODE	ENDS
	END
